package com.vilen.learn.java7.V4.V4_3;

import com.vilen.learn.java7.V4.Author;
import com.vilen.learn.java7.V4.SimpleMicroBlogNode;
import com.vilen.learn.java7.V4.Update;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by vilen on 2017/10/2.
 */
public class DeadlockWithLockMicroBlogNode implements SimpleMicroBlogNode{
    public DeadlockWithLockMicroBlogNode(String ident_) {
        ident = ident_;
    }

    private static Update getUpdate(String s) {
        Update.Builder b = new Update.Builder();
        b.updateText(s).author(new Author("Ben"));
        return b.build();
    }

    private final String ident;
    private final Lock lock = new ReentrantLock();

    public String getIdent() {
        return ident;
    }

    @Override
    public void propagateUpdate(Update upd_, SimpleMicroBlogNode backup_) {
        //每个线程都先锁住自己的锁
        lock.lock();
        try {
            System.out.println(ident+": recvd: "+upd_.getUpdateText()
            + " ; backup: "+backup_.getIdent());
            //调用confirmUpdate()知悉其他线程
            backup_.confirmUpdate(this,upd_);
        }finally {
            lock.unlock();
        }
    }

    @Override
    public void confirmUpdate(SimpleMicroBlogNode other_, Update upd_) {
        lock.lock();
        try{
            System.out.println(ident+": recvd: "+upd_.getUpdateText()
                    + " ; backup: "+other_.getIdent());
        }finally {
            lock.unlock();
        }
    }

    public static void main(String[] a) {
        final DeadlockWithLockMicroBlogNode local = new DeadlockWithLockMicroBlogNode(
                "localhost:8888");
        final DeadlockWithLockMicroBlogNode other = new DeadlockWithLockMicroBlogNode(
                "localhost:8988");
        final Update first = getUpdate("1");
        final Update second = getUpdate("2");

        new Thread(new Runnable() {
            public void run() {
                local.propagateUpdate(first, other);
            }
        }).start();

        new Thread(new Runnable() {
            public void run() {
                other.propagateUpdate(second, local);
            }
        }).start();
    }
}
